using System.Collections.Generic;
using NUnit.Framework;
using Tycho.Lexer;
using Tycho.Parser.Peg;
using Tycho.Parser.Tokens;

namespace Tycho.Parser.Tests.Peg {
    [TestFixture]
    public class SequenceRuleSpecification {
        [Test]
        public void ShouldReturnTermAndIncrementIndexWhenParsed () {
            var sequence = new SequenceRule<object> (new KeywordRule<object> ("a"), new KeywordRule<object> ("b"), new KeywordRule<object> ("c"));

            List<Token> tokens = NativeLexer.Lex ("a b c");

            var result = sequence.Parse (tokens.ToArray (), 0, null);
            Assert.IsNotNull (result);
            Assert.AreEqual (3, result.Index);
        }

        [Test]
        public void ShouldReturnNullAndDontIncrementIndexWhenCannotParse () {
            var sequence = new SequenceRule<object> (new KeywordRule<object> ("a"), new KeywordRule<object> ("b"), new KeywordRule<object> ("c"));

            List<Token> tokens = NativeLexer.Lex ("a b x");

            var result = sequence.Parse (tokens.ToArray (), 0, null);
            Assert.IsNull (result);
        }

        [Test]
        public void ShouldAddSubNodesToReturnedCompositeTermWhenParsed () {
            var nonTerminal = new SequenceRule<object> (
                new NamedRule<object> ("a", new IdentifierTerminal<object> ()),
                new KeywordRule<object> ("="),
                new NamedRule<object> ("b", new IdentifierTerminal<object> ()));

            List<Token> tokens = NativeLexer.Lex ("x = y");

            var result = nonTerminal.Parse (tokens.ToArray (), 0, null);
            Assert.IsNotNull (result);
            Assert.AreEqual (3, result.Index);

            Assert.AreEqual (2, result.Captures.Count);
            result.AssertCaptureIs (0, "a", "x");
            result.AssertCaptureIs (1, "b", "y");
        }

        [Test]
        public void ShouldPassContextFromOneRuleToTheNext () {
            var id1 = new IdentifierTerminal<int> ();
            id1.Action = (t, i) => i + 1;
            var id2 = new IdentifierTerminal<int> ();
            id2.Action = (t, i) => i + 1;
            var id3 = new IdentifierTerminal<int> ();
            id3.Action = (t, i) => i + 1;

            var nonTerminal = new SequenceRule<int> (
                new NamedRule<int> ("a", id1),
                new NamedRule<int> ("b", id2),
                new NamedRule<int> ("c", id3));

            List<Token> tokens = NativeLexer.Lex ("a b x");

            var result = nonTerminal.Parse (tokens.ToArray (), 0, 0);
            Assert.IsNotNull (result);
            Assert.AreEqual (3, result.Context);
        }
    }
}